package org.g4studio.core.net.ftp;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

import org.g4studio.core.net.MalformedServerReplyException;
import org.g4studio.core.net.ftp.parser.DefaultFTPFileEntryParserFactory;
import org.g4studio.core.net.ftp.parser.FTPFileEntryParserFactory;
import org.g4studio.core.net.ftp.parser.ParserInitializationException;
import org.g4studio.core.net.io.CopyStreamEvent;
import org.g4studio.core.net.io.CopyStreamException;
import org.g4studio.core.net.io.FromNetASCIIInputStream;
import org.g4studio.core.net.io.SocketInputStream;
import org.g4studio.core.net.io.SocketOutputStream;
import org.g4studio.core.net.io.ToNetASCIIOutputStream;
import org.g4studio.core.net.io.Util;

/***
 * FTPClient encapsulates all the functionality necessary to store and retrieve
 * files from an FTP server. This class takes care of all low level details of
 * interacting with an FTP server and provides a convenient higher level
 * interface. As with all classes derived from
 * {@link org.apache.commons.net.SocketClient}, you must first connect to the
 * server with {@link org.apache.commons.net.SocketClient#connect connect }
 * before doing anything, and finally
 * {@link org.apache.commons.net.SocketClient#disconnect disconnect } after
 * you're completely finished interacting with the server. Then you need to
 * check the FTP reply code to see if the connection was successful. For
 * example:
 * 
 * <pre>
 *    boolean error = false;
 *    try {
 *      int reply;
 *      ftp.connect("ftp.foobar.com");
 *      System.out.println("Connected to " + server + ".");
 *      System.out.print(ftp.getReplyString());
 * 
 *      // After connection attempt, you should check the reply code to verify
 *      // success.
 *      reply = ftp.getReplyCode();
 * 
 *      if(!FTPReply.isPositiveCompletion(reply)) {
 *        ftp.disconnect();
 *        System.err.println("FTP server refused connection.");
 *        System.exit(1);
 *      }
 *      ... // transfer files
 *      ftp.logout();
 *    } catch(IOException e) {
 *      error = true;
 *      e.printStackTrace();
 *    } finally {
 *      if(ftp.isConnected()) {
 *        try {
 *          ftp.disconnect();
 *        } catch(IOException ioe) {
 *          // do nothing
 *        }
 *      }
 *      System.exit(error ? 1 : 0);
 *    }
 * </pre>
 * <p>
 * Immediately after connecting is the only real time you need to check the
 * reply code (because connect is of type void). The convention for all the FTP
 * command methods in FTPClient is such that they either return a boolean value
 * or some other value. The boolean methods return true on a successful
 * completion reply from the FTP server and false on a reply resulting in an
 * error condition or failure. The methods returning a value other than boolean
 * return a value containing the higher level data produced by the FTP command,
 * or null if a reply resulted in an error condition or failure. If you want to
 * access the exact FTP reply code causing a success or failure, you must call
 * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode } after a
 * success or failure.
 * <p>
 * The default settings for FTPClient are for it to use
 * <code> FTP.ASCII_FILE_TYPE </code>, <code> FTP.NON_PRINT_TEXT_FORMAT </code>,
 * <code> FTP.STREAM_TRANSFER_MODE </code>, and
 * <code> FTP.FILE_STRUCTURE </code>. The only file types directly supported are
 * <code> FTP.ASCII_FILE_TYPE </code> and <code> FTP.IMAGE_FILE_TYPE </code>
 * (which is the same as <code> FTP.BINARY_FILE_TYPE </code>). Because there are
 * at lest 4 different EBCDIC encodings, we have opted not to provide direct
 * support for EBCDIC. To transfer EBCDIC and other unsupported file types you
 * must create your own filter InputStreams and OutputStreams and wrap them
 * around the streams returned or required by the FTPClient methods. FTPClient
 * uses the {@link ToNetASCIIOutputStream NetASCII} filter streams to provide
 * transparent handling of ASCII files. We will consider incorporating EBCDIC
 * support if there is enough demand.
 * <p>
 * <code> FTP.NON_PRINT_TEXT_FORMAT </code>,
 * <code> FTP.STREAM_TRANSFER_MODE </code>, and
 * <code> FTP.FILE_STRUCTURE </code> are the only supported formats, transfer
 * modes, and file structures.
 * <p>
 * Because the handling of sockets on different platforms can differ
 * significantly, the FTPClient automatically issues a new PORT command prior to
 * every transfer requiring that the server connect to the client's data port.
 * This ensures identical problem-free behavior on Windows, Unix, and Macintosh
 * platforms. Additionally, it relieves programmers from having to issue the
 * PORT command themselves and dealing with platform dependent issues.
 * <p>
 * Additionally, for security purposes, all data connections to the client are
 * verified to ensure that they originated from the intended party (host and
 * port). If a data connection is initiated by an unexpected party, the command
 * will close the socket and throw an IOException. You may disable this behavior
 * with {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()}.
 * <p>
 * You should keep in mind that the FTP server may choose to prematurely close a
 * connection if the client has been idle for longer than a given time period
 * (usually 900 seconds). The FTPClient class will detect a premature FTP server
 * connection closing when it receives a
 * {@link org.apache.commons.net.ftp.FTPReply#SERVICE_NOT_AVAILABLE
 * FTPReply.SERVICE_NOT_AVAILABLE } response to a command. When that occurs, the
 * FTP class method encountering that reply will throw an
 * {@link org.apache.commons.net.ftp.FTPConnectionClosedException} .
 * <code>FTPConnectionClosedException</code> is a subclass of
 * <code> IOException </code> and therefore need not be caught separately, but
 * if you are going to catch it separately, its catch block must appear before
 * the more general <code> IOException </code> catch block. When you encounter
 * an {@link org.apache.commons.net.ftp.FTPConnectionClosedException} , you must
 * disconnect the connection with {@link #disconnect disconnect() } to properly
 * clean up the system resources used by FTPClient. Before disconnecting, you
 * may check the last reply code and text with
 * {@link org.apache.commons.net.ftp.FTP#getReplyCode getReplyCode },
 * {@link org.apache.commons.net.ftp.FTP#getReplyString getReplyString }, and
 * {@link org.apache.commons.net.ftp.FTP#getReplyStrings getReplyStrings}. You
 * may avoid server disconnections while the client is idle by periodicaly
 * sending NOOP commands to the server.
 * <p>
 * Rather than list it separately for each method, we mention here that every
 * method communicating with the server and throwing an IOException can also
 * throw a {@link org.apache.commons.net.MalformedServerReplyException} , which
 * is a subclass of IOException. A MalformedServerReplyException will be thrown
 * when the reply received from the server deviates enough from the protocol
 * specification that it cannot be interpreted in a useful manner despite
 * attempts to be as lenient as possible.
 * <p>
 * Listing API Examples Both paged and unpaged examples of directory listings
 * are available, as follows:
 * <p>
 * Unpaged (whole list) access, using a parser accessible by auto-detect:
 * 
 * <pre>
 * FTPClient f = FTPClient();
 * f.connect(server);
 * f.login(username, password);
 * FTPFile[] files = listFiles(directory);
 * </pre>
 * <p>
 * Paged access, using a parser not accessible by auto-detect. The class defined
 * in the first parameter of initateListParsing should be derived from
 * org.apache.commons.net.FTPFileEntryParser:
 * 
 * <pre>
 * FTPClient f = FTPClient();
 * f.connect(server);
 * f.login(username, password);
 * FTPListParseEngine engine = f.initiateListParsing(&quot;com.whatever.YourOwnParser&quot;, directory);
 * 
 * while (engine.hasNext()) {
 * 	FTPFile[] files = engine.getNext(25); // &quot;page size&quot; you want
 * 	// do whatever you want with these files, display them, etc.
 * 	// expensive FTPFile objects not created until needed.
 * }
 * </pre>
 * <p>
 * Paged access, using a parser accessible by auto-detect:
 * 
 * <pre>
 * FTPClient f = FTPClient();
 * f.connect(server);
 * f.login(username, password);
 * FTPListParseEngine engine = f.initiateListParsing(directory);
 * 
 * while (engine.hasNext()) {
 * 	FTPFile[] files = engine.getNext(25); // &quot;page size&quot; you want
 * 	// do whatever you want with these files, display them, etc.
 * 	// expensive FTPFile objects not created until needed.
 * }
 * </pre>
 * <p>
 * For examples of using FTPClient on servers whose directory listings
 * <ul>
 * <li>use languages other than English</li>
 * <li>use date formats other than the American English "standard"
 * <code>MM d yyyy</code></li>
 * <li>are in different timezones and you need accurate timestamps for
 * dependency checking as in Ant</li>
 * </ul>
 * see {@link FTPClientConfig FTPClientConfig}.
 * <p>
 * NOTE: If you experience problems with unwanted firing of
 * 
 * <pre>
 * setSoTimeout()
 * </pre>
 * 
 * during periods of client inactivity, this can be alleviated by calling
 * 
 * <pre>
 * setReaderThread(false)
 * </pre>
 * 
 * . For more details, see <a
 * href="http://issues.apache.org/bugzilla/show_bug.cgi?id=31122">this
 * thread</a>.
 * </p>
 * <p>
 * 
 * @author Daniel F. Savarese
 * @see FTP
 * @see FTPConnectionClosedException
 * @see FTPFileEntryParser
 * @see FTPFileEntryParserFactory
 * @see DefaultFTPFileEntryParserFactory
 * @see FTPClientConfig
 * @see org.apache.commons.net.MalformedServerReplyException
 **/
public class FTPClient extends FTP implements Configurable {
	/***
	 * A constant indicating the FTP session is expecting all transfers to occur
	 * between the client (local) and server and that the server should connect
	 * to the client's data port to initiate a data transfer. This is the
	 * default data connection mode when and FTPClient instance is created.
	 ***/
	public static final int ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0;
	/***
	 * A constant indicating the FTP session is expecting all transfers to occur
	 * between two remote servers and that the server the client is connected to
	 * should connect to the other server's data port to initiate a data
	 * transfer.
	 ***/
	public static final int ACTIVE_REMOTE_DATA_CONNECTION_MODE = 1;
	/***
	 * A constant indicating the FTP session is expecting all transfers to occur
	 * between the client (local) and server and that the server is in passive
	 * mode, requiring the client to connect to the server's data port to
	 * initiate a transfer.
	 ***/
	public static final int PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2;
	/***
	 * A constant indicating the FTP session is expecting all transfers to occur
	 * between two remote servers and that the server the client is connected to
	 * is in passive mode, requiring the other server to connect to the first
	 * server's data port to initiate a data transfer.
	 ***/
	public static final int PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3;

	private int __dataConnectionMode, __dataTimeout;
	private int __passivePort;
	private String __passiveHost;
	private int __fileType, __fileFormat, __fileStructure, __fileTransferMode;
	private boolean __remoteVerificationEnabled;
	private long __restartOffset;
	private FTPFileEntryParserFactory __parserFactory;
	private int __bufferSize;

	// __systemName is a cached value that should not be referenced directly
	// except when assigned in getSystemName and __initDefaults.
	private String __systemName;

	// __entryParser is a cached value that should not be referenced directly
	// except when assigned in listFiles(String, String) and __initDefaults.
	private FTPFileEntryParser __entryParser;

	private FTPClientConfig __configuration;

	/***
	 * Default FTPClient constructor. Creates a new FTPClient instance with the
	 * data connection mode set to
	 * <code> ACTIVE_LOCAL_DATA_CONNECTION_MODE </code>, the file type set to
	 * <code> FTP.ASCII_FILE_TYPE </code>, the file format set to
	 * <code> FTP.NON_PRINT_TEXT_FORMAT </code>, the file structure set to
	 * <code> FTP.FILE_STRUCTURE </code>, and the transfer mode set to
	 * <code> FTP.STREAM_TRANSFER_MODE </code>.
	 ***/
	public FTPClient() {
		__initDefaults();
		__dataTimeout = -1;
		__remoteVerificationEnabled = true;
		__parserFactory = new DefaultFTPFileEntryParserFactory();
		__configuration = null;
	}

	private void __initDefaults() {
		__dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE;
		__passiveHost = null;
		__passivePort = -1;
		__fileType = FTP.ASCII_FILE_TYPE;
		__fileStructure = FTP.FILE_STRUCTURE;
		__fileFormat = FTP.NON_PRINT_TEXT_FORMAT;
		__fileTransferMode = FTP.STREAM_TRANSFER_MODE;
		__restartOffset = 0;
		__systemName = null;
		__entryParser = null;
		__bufferSize = Util.DEFAULT_COPY_BUFFER_SIZE;
	}

	private String __parsePathname(String reply) {
		int begin, end;

		begin = reply.indexOf('"') + 1;
		end = reply.indexOf('"', begin);

		return reply.substring(begin, end);
	}

	private void __parsePassiveModeReply(String reply) throws MalformedServerReplyException {
		int i, index, lastIndex;
		String octet1, octet2;
		StringBuffer host;

		reply = reply.substring(reply.indexOf('(') + 1, reply.indexOf(')')).trim();

		host = new StringBuffer(24);
		lastIndex = 0;
		index = reply.indexOf(',');
		host.append(reply.substring(lastIndex, index));

		for (i = 0; i < 3; i++) {
			host.append('.');
			lastIndex = index + 1;
			index = reply.indexOf(',', lastIndex);
			host.append(reply.substring(lastIndex, index));
		}

		lastIndex = index + 1;
		index = reply.indexOf(',', lastIndex);

		octet1 = reply.substring(lastIndex, index);
		octet2 = reply.substring(index + 1);

		// index and lastIndex now used as temporaries
		try {
			index = Integer.parseInt(octet1);
			lastIndex = Integer.parseInt(octet2);
		} catch (NumberFormatException e) {
			throw new MalformedServerReplyException("Could not parse passive host information.\nServer Reply: " + reply);
		}

		index <<= 8;
		index |= lastIndex;

		__passiveHost = host.toString();
		__passivePort = index;
	}

	private boolean __storeFile(int command, String remote, InputStream local) throws IOException {
		OutputStream output;
		Socket socket;

		if ((socket = _openDataConnection_(command, remote)) == null)
			return false;

		output = new BufferedOutputStream(socket.getOutputStream(), getBufferSize());
		if (__fileType == ASCII_FILE_TYPE)
			output = new ToNetASCIIOutputStream(output);
		// Treat everything else as binary for now
		try {
			Util.copyStream(local, output, getBufferSize(), CopyStreamEvent.UNKNOWN_STREAM_SIZE, null, false);
		} catch (IOException e) {
			try {
				socket.close();
			} catch (IOException f) {
			}
			throw e;
		}
		output.close();
		socket.close();
		return completePendingCommand();
	}

	private OutputStream __storeFileStream(int command, String remote) throws IOException {
		OutputStream output;
		Socket socket;

		if ((socket = _openDataConnection_(command, remote)) == null)
			return null;

		output = socket.getOutputStream();
		if (__fileType == ASCII_FILE_TYPE) {
			// We buffer ascii transfers because the buffering has to
			// be interposed between ToNetASCIIOutputSream and the underlying
			// socket output stream. We don't buffer binary transfers
			// because we don't want to impose a buffering policy on the
			// programmer if possible. Programmers can decide on their
			// own if they want to wrap the SocketOutputStream we return
			// for file types other than ASCII.
			output = new BufferedOutputStream(output, getBufferSize());
			output = new ToNetASCIIOutputStream(output);

		}
		return new SocketOutputStream(socket, output);
	}

	/**
	 * Establishes a data connection with the FTP server, returning a Socket for
	 * the connection if successful. If a restart offset has been set with
	 * {@link #setRestartOffset(long)}, a REST command is issued to the server
	 * with the offset as an argument before establishing the data connection.
	 * Active mode connections also cause a local PORT command to be issued.
	 * <p>
	 * 
	 * @param command
	 *            The text representation of the FTP command to send.
	 * @param arg
	 *            The arguments to the FTP command. If this parameter is set to
	 *            null, then the command is sent with no argument.
	 * @return A Socket corresponding to the established data connection. Null
	 *         is returned if an FTP protocol error is reported at any point
	 *         during the establishment and initialization of the connection.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 */
	protected Socket _openDataConnection_(int command, String arg) throws IOException {
		Socket socket;

		if (__dataConnectionMode != ACTIVE_LOCAL_DATA_CONNECTION_MODE
				&& __dataConnectionMode != PASSIVE_LOCAL_DATA_CONNECTION_MODE)
			return null;

		if (__dataConnectionMode == ACTIVE_LOCAL_DATA_CONNECTION_MODE) {
			ServerSocket server;
			server = _socketFactory_.createServerSocket(0, 1, getLocalAddress());

			if (!FTPReply.isPositiveCompletion(port(getLocalAddress(), server.getLocalPort()))) {
				server.close();
				return null;
			}

			if ((__restartOffset > 0) && !restart(__restartOffset)) {
				server.close();
				return null;
			}

			if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) {
				server.close();
				return null;
			}

			// For now, let's just use the data timeout value for waiting for
			// the data connection. It may be desirable to let this be a
			// separately configurable value. In any case, we really want
			// to allow preventing the accept from blocking indefinitely.
			if (__dataTimeout >= 0)
				server.setSoTimeout(__dataTimeout);
			socket = server.accept();
			server.close();
		} else { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE

			if (pasv() != FTPReply.ENTERING_PASSIVE_MODE)
				return null;

			__parsePassiveModeReply((String) _replyLines.elementAt(0));

			socket = _socketFactory_.createSocket(__passiveHost, __passivePort);
			if ((__restartOffset > 0) && !restart(__restartOffset)) {
				socket.close();
				return null;
			}

			if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) {
				socket.close();
				return null;
			}
		}

		if (__remoteVerificationEnabled && !verifyRemote(socket)) {
			InetAddress host1, host2;

			host1 = socket.getInetAddress();
			host2 = getRemoteAddress();

			socket.close();

			throw new IOException("Host attempting data connection " + host1.getHostAddress()
					+ " is not same as server " + host2.getHostAddress());
		}

		if (__dataTimeout >= 0)
			socket.setSoTimeout(__dataTimeout);

		return socket;
	}

	protected void _connectAction_() throws IOException {
		super._connectAction_();
		__initDefaults();
	}

	/***
	 * Sets the timeout in milliseconds to use when reading from the data
	 * connection. This timeout will be set immediately after opening the data
	 * connection.
	 * <p>
	 * 
	 * @param timeout
	 *            The default timeout in milliseconds that is used when opening
	 *            a data connection socket.
	 ***/
	public void setDataTimeout(int timeout) {
		__dataTimeout = timeout;
	}

	/**
	 * set the factory used for parser creation to the supplied factory object.
	 * 
	 * @param parserFactory
	 *            factory object used to create FTPFileEntryParsers
	 * 
	 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
	 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
	 */
	public void setParserFactory(FTPFileEntryParserFactory parserFactory) {
		__parserFactory = parserFactory;
	}

	/***
	 * Closes the connection to the FTP server and restores connection
	 * parameters to the default values.
	 * <p>
	 * 
	 * @exception IOException
	 *                If an error occurs while disconnecting.
	 ***/
	public void disconnect() throws IOException {
		super.disconnect();
		__initDefaults();
	}

	/***
	 * Enable or disable verification that the remote host taking part of a data
	 * connection is the same as the host to which the control connection is
	 * attached. The default is for verification to be enabled. You may set this
	 * value at any time, whether the FTPClient is currently connected or not.
	 * <p>
	 * 
	 * @param enable
	 *            True to enable verification, false to disable verification.
	 ***/
	public void setRemoteVerificationEnabled(boolean enable) {
		__remoteVerificationEnabled = enable;
	}

	/***
	 * Return whether or not verification of the remote host participating in
	 * data connections is enabled. The default behavior is for verification to
	 * be enabled.
	 * <p>
	 * 
	 * @return True if verification is enabled, false if not.
	 ***/
	public boolean isRemoteVerificationEnabled() {
		return __remoteVerificationEnabled;
	}

	/***
	 * Login to the FTP server using the provided username and password.
	 * <p>
	 * 
	 * @param username
	 *            The username to login under.
	 * @param password
	 *            The password to use.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean login(String username, String password) throws IOException {
		user(username);

		if (FTPReply.isPositiveCompletion(_replyCode))
			return true;

		// If we get here, we either have an error code, or an intermmediate
		// reply requesting password.
		if (!FTPReply.isPositiveIntermediate(_replyCode))
			return false;

		return FTPReply.isPositiveCompletion(pass(password));
	}

	/***
	 * Login to the FTP server using the provided username, password, and
	 * account. If no account is required by the server, only the username and
	 * password, the account information is not used.
	 * <p>
	 * 
	 * @param username
	 *            The username to login under.
	 * @param password
	 *            The password to use.
	 * @param account
	 *            The account to use.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean login(String username, String password, String account) throws IOException {
		user(username);

		if (FTPReply.isPositiveCompletion(_replyCode))
			return true;

		// If we get here, we either have an error code, or an intermmediate
		// reply requesting password.
		if (!FTPReply.isPositiveIntermediate(_replyCode))
			return false;

		pass(password);

		if (FTPReply.isPositiveCompletion(_replyCode))
			return true;

		if (!FTPReply.isPositiveIntermediate(_replyCode))
			return false;

		return FTPReply.isPositiveCompletion(acct(account));
	}

	/***
	 * Logout of the FTP server by sending the QUIT command.
	 * <p>
	 * 
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean logout() throws IOException {
		return FTPReply.isPositiveCompletion(quit());
	}

	/***
	 * Change the current working directory of the FTP session.
	 * <p>
	 * 
	 * @param pathname
	 *            The new current working directory.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean changeWorkingDirectory(String pathname) throws IOException {
		return FTPReply.isPositiveCompletion(cwd(pathname));
	}

	/***
	 * Change to the parent directory of the current working directory.
	 * <p>
	 * 
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean changeToParentDirectory() throws IOException {
		return FTPReply.isPositiveCompletion(cdup());
	}

	/***
	 * Issue the FTP SMNT command.
	 * <p>
	 * 
	 * @param pathname
	 *            The pathname to mount.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean structureMount(String pathname) throws IOException {
		return FTPReply.isPositiveCompletion(smnt(pathname));
	}

	/***
	 * Reinitialize the FTP session. Not all FTP servers support this command,
	 * which issues the FTP REIN command.
	 * <p>
	 * 
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	boolean reinitialize() throws IOException {
		rein();

		if (FTPReply.isPositiveCompletion(_replyCode)
				|| (FTPReply.isPositivePreliminary(_replyCode) && FTPReply.isPositiveCompletion(getReply()))) {

			__initDefaults();

			return true;
		}

		return false;
	}

	/***
	 * Set the current data connection mode to
	 * <code>ACTIVE_LOCAL_DATA_CONNECTION_MODE</code>. No communication with the
	 * FTP server is conducted, but this causes all future data transfers to
	 * require the FTP server to connect to the client's data port.
	 * Additionally, to accommodate differences between socket implementations
	 * on different platforms, this method causes the client to issue a PORT
	 * command before every data transfer.
	 ***/
	public void enterLocalActiveMode() {
		__dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE;
		__passiveHost = null;
		__passivePort = -1;
	}

	/***
	 * Set the current data connection mode to
	 * <code> PASSIVE_LOCAL_DATA_CONNECTION_MODE </code>. Use this method only
	 * for data transfers between the client and server. This method causes a
	 * PASV command to be issued to the server before the opening of every data
	 * connection, telling the server to open a data port to which the client
	 * will connect to conduct data transfers. The FTPClient will stay in
	 * <code> PASSIVE_LOCAL_DATA_CONNECTION_MODE </code> until the mode is
	 * changed by calling some other method such as
	 * {@link #enterLocalActiveMode enterLocalActiveMode() }
	 ***/
	public void enterLocalPassiveMode() {
		__dataConnectionMode = PASSIVE_LOCAL_DATA_CONNECTION_MODE;
		// These will be set when just before a data connection is opened
		// in _openDataConnection_()
		__passiveHost = null;
		__passivePort = -1;
	}

	/***
	 * Set the current data connection mode to
	 * <code> ACTIVE_REMOTE_DATA_CONNECTION </code>. Use this method only for
	 * server to server data transfers. This method issues a PORT command to the
	 * server, indicating the other server and port to which it should connect
	 * for data transfers. You must call this method before EVERY server to
	 * server transfer attempt. The FTPClient will NOT automatically continue to
	 * issue PORT commands. You also must remember to call
	 * {@link #enterLocalActiveMode enterLocalActiveMode() } if you wish to
	 * return to the normal data connection mode.
	 * <p>
	 * 
	 * @param host
	 *            The passive mode server accepting connections for data
	 *            transfers.
	 * @param port
	 *            The passive mode server's data port.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean enterRemoteActiveMode(InetAddress host, int port) throws IOException {
		if (FTPReply.isPositiveCompletion(port(host, port))) {
			__dataConnectionMode = ACTIVE_REMOTE_DATA_CONNECTION_MODE;
			__passiveHost = null;
			__passivePort = -1;
			return true;
		}
		return false;
	}

	/***
	 * Set the current data connection mode to
	 * <code> PASSIVE_REMOTE_DATA_CONNECTION_MODE </code>. Use this method only
	 * for server to server data transfers. This method issues a PASV command to
	 * the server, telling it to open a data port to which the active server
	 * will connect to conduct data transfers. You must call this method before
	 * EVERY server to server transfer attempt. The FTPClient will NOT
	 * automatically continue to issue PASV commands. You also must remember to
	 * call {@link #enterLocalActiveMode enterLocalActiveMode() } if you wish to
	 * return to the normal data connection mode.
	 * <p>
	 * 
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean enterRemotePassiveMode() throws IOException {
		if (pasv() != FTPReply.ENTERING_PASSIVE_MODE)
			return false;

		__dataConnectionMode = PASSIVE_REMOTE_DATA_CONNECTION_MODE;
		__parsePassiveModeReply((String) _replyLines.elementAt(0));

		return true;
	}

	/***
	 * Returns the hostname or IP address (in the form of a string) returned by
	 * the server when entering passive mode. If not in passive mode, returns
	 * null. This method only returns a valid value AFTER a data connection has
	 * been opened after a call to {@link #enterLocalPassiveMode
	 * enterLocalPassiveMode()}. This is because FTPClient sends a PASV command
	 * to the server only just before opening a data connection, and not when
	 * you call {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
	 * <p>
	 * 
	 * @return The passive host name if in passive mode, otherwise null.
	 ***/
	public String getPassiveHost() {
		return __passiveHost;
	}

	/***
	 * If in passive mode, returns the data port of the passive host. This
	 * method only returns a valid value AFTER a data connection has been opened
	 * after a call to {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
	 * This is because FTPClient sends a PASV command to the server only just
	 * before opening a data connection, and not when you call
	 * {@link #enterLocalPassiveMode enterLocalPassiveMode()}.
	 * <p>
	 * 
	 * @return The data port of the passive server. If not in passive mode,
	 *         undefined.
	 ***/
	public int getPassivePort() {
		return __passivePort;
	}

	/***
	 * Returns the current data connection mode (one of the
	 * <code> _DATA_CONNECTION_MODE </code> constants.
	 * <p>
	 * 
	 * @return The current data connection mode (one of the
	 *         <code> _DATA_CONNECTION_MODE </code> constants.
	 ***/
	public int getDataConnectionMode() {
		return __dataConnectionMode;
	}

	/***
	 * Sets the file type to be transferred. This should be one of
	 * <code> FTP.ASCII_FILE_TYPE </code>, <code> FTP.IMAGE_FILE_TYPE </code>,
	 * etc. The file type only needs to be set when you want to change the type.
	 * After changing it, the new type stays in effect until you change it
	 * again. The default file type is <code> FTP.ASCII_FILE_TYPE </code> if
	 * this method is never called.
	 * <p>
	 * 
	 * @param fileType
	 *            The <code> _FILE_TYPE </code> constant indcating the type of
	 *            file.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean setFileType(int fileType) throws IOException {
		if (FTPReply.isPositiveCompletion(type(fileType))) {
			__fileType = fileType;
			__fileFormat = FTP.NON_PRINT_TEXT_FORMAT;
			return true;
		}
		return false;
	}

	/***
	 * Sets the file type to be transferred and the format. The type should be
	 * one of <code> FTP.ASCII_FILE_TYPE </code>,
	 * <code> FTP.IMAGE_FILE_TYPE </code>, etc. The file type only needs to be
	 * set when you want to change the type. After changing it, the new type
	 * stays in effect until you change it again. The default file type is
	 * <code> FTP.ASCII_FILE_TYPE </code> if this method is never called. The
	 * format should be one of the FTP class <code> TEXT_FORMAT </code>
	 * constants, or if the type is <code> FTP.LOCAL_FILE_TYPE </code>, the
	 * format should be the byte size for that type. The default format is
	 * <code> FTP.NON_PRINT_TEXT_FORMAT </code> if this method is never called.
	 * <p>
	 * 
	 * @param fileType
	 *            The <code> _FILE_TYPE </code> constant indcating the type of
	 *            file.
	 * @param formatOrByteSize
	 *            The format of the file (one of the <code>_FORMAT</code>
	 *            constants. In the case of <code>LOCAL_FILE_TYPE</code>, the
	 *            byte size.
	 *            <p>
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean setFileType(int fileType, int formatOrByteSize) throws IOException {
		if (FTPReply.isPositiveCompletion(type(fileType, formatOrByteSize))) {
			__fileType = fileType;
			__fileFormat = formatOrByteSize;
			return true;
		}
		return false;
	}

	/***
	 * Sets the file structure. The default structure is
	 * <code> FTP.FILE_STRUCTURE </code> if this method is never called.
	 * <p>
	 * 
	 * @param structure
	 *            The structure of the file (one of the FTP class
	 *            <code>_STRUCTURE</code> constants).
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean setFileStructure(int structure) throws IOException {
		if (FTPReply.isPositiveCompletion(stru(structure))) {
			__fileStructure = structure;
			return true;
		}
		return false;
	}

	/***
	 * Sets the transfer mode. The default transfer mode
	 * <code> FTP.STREAM_TRANSFER_MODE </code> if this method is never called.
	 * <p>
	 * 
	 * @param mode
	 *            The new transfer mode to use (one of the FTP class
	 *            <code>_TRANSFER_MODE</code> constants).
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean setFileTransferMode(int mode) throws IOException {
		if (FTPReply.isPositiveCompletion(mode(mode))) {
			__fileTransferMode = mode;
			return true;
		}
		return false;
	}

	/***
	 * Initiate a server to server file transfer. This method tells the server
	 * to which the client is connected to retrieve a given file from the other
	 * server.
	 * <p>
	 * 
	 * @param filename
	 *            The name of the file to retrieve.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean remoteRetrieve(String filename) throws IOException {
		if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE
				|| __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE)
			return FTPReply.isPositivePreliminary(retr(filename));
		return false;
	}

	/***
	 * Initiate a server to server file transfer. This method tells the server
	 * to which the client is connected to store a file on the other server
	 * using the given filename. The other server must have had a
	 * <code> remoteRetrieve </code> issued to it by another FTPClient.
	 * <p>
	 * 
	 * @param filename
	 *            The name to call the file that is to be stored.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean remoteStore(String filename) throws IOException {
		if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE
				|| __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE)
			return FTPReply.isPositivePreliminary(stor(filename));
		return false;
	}

	/***
	 * Initiate a server to server file transfer. This method tells the server
	 * to which the client is connected to store a file on the other server
	 * using a unique filename based on the given filename. The other server
	 * must have had a <code> remoteRetrieve </code> issued to it by another
	 * FTPClient.
	 * <p>
	 * 
	 * @param filename
	 *            The name on which to base the filename of the file that is to
	 *            be stored.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean remoteStoreUnique(String filename) throws IOException {
		if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE
				|| __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE)
			return FTPReply.isPositivePreliminary(stou(filename));
		return false;
	}

	/***
	 * Initiate a server to server file transfer. This method tells the server
	 * to which the client is connected to store a file on the other server
	 * using a unique filename. The other server must have had a
	 * <code> remoteRetrieve </code> issued to it by another FTPClient. Many FTP
	 * servers require that a base filename be given from which the unique
	 * filename can be derived. For those servers use the other version of
	 * <code> remoteStoreUnique</code>
	 * <p>
	 * 
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean remoteStoreUnique() throws IOException {
		if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE
				|| __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE)
			return FTPReply.isPositivePreliminary(stou());
		return false;
	}

	// For server to server transfers
	/***
	 * Initiate a server to server file transfer. This method tells the server
	 * to which the client is connected to append to a given file on the other
	 * server. The other server must have had a <code> remoteRetrieve </code>
	 * issued to it by another FTPClient.
	 * <p>
	 * 
	 * @param filename
	 *            The name of the file to be appended to, or if the file does
	 *            not exist, the name to call the file being stored.
	 *            <p>
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean remoteAppend(String filename) throws IOException {
		if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE
				|| __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE)
			return FTPReply.isPositivePreliminary(stor(filename));
		return false;
	}

	/***
	 * There are a few FTPClient methods that do not complete the entire
	 * sequence of FTP commands to complete a transaction. These commands
	 * require some action by the programmer after the reception of a positive
	 * intermediate command. After the programmer's code completes its actions,
	 * it must call this method to receive the completion reply from the server
	 * and verify the success of the entire transaction.
	 * <p>
	 * For example,
	 * 
	 * <pre>
	 * InputStream input;
	 * OutputStream output;
	 * input  = new FileInputStream("foobaz.txt");
	 * output = ftp.storeFileStream("foobar.txt")
	 * if(!FTPReply.isPositiveIntermediate(ftp.getReplyCode())) {
	 *     input.close();
	 *     output.close();
	 *     ftp.logout();
	 *     ftp.disconnect();
	 *     System.err.println("File transfer failed.");
	 *     System.exit(1);
	 * }
	 * Util.copyStream(input, output);
	 * input.close();
	 * output.close();
	 * // Must call completePendingCommand() to finish command.
	 * if(!ftp.completePendingCommand()) {
	 *     ftp.logout();
	 *     ftp.disconnect();
	 *     System.err.println("File transfer failed.");
	 *     System.exit(1);
	 * }
	 * </pre>
	 * <p>
	 * 
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean completePendingCommand() throws IOException {
		return FTPReply.isPositiveCompletion(getReply());
	}

	/***
	 * Retrieves a named file from the server and writes it to the given
	 * OutputStream. This method does NOT close the given OutputStream. If the
	 * current file type is ASCII, line separators in the file are converted to
	 * the local representation.
	 * <p>
	 * 
	 * @param remote
	 *            The name of the remote file.
	 * @param local
	 *            The local OutputStream to which to write the file.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception CopyStreamException
	 *                If an I/O error occurs while actually transferring the
	 *                file. The CopyStreamException allows you to determine the
	 *                number of bytes transferred and the IOException causing
	 *                the error. This exception may be caught either as an
	 *                IOException or independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean retrieveFile(String remote, OutputStream local) throws IOException {
		InputStream input;
		Socket socket;

		if ((socket = _openDataConnection_(FTPCommand.RETR, remote)) == null)
			return false;

		input = new BufferedInputStream(socket.getInputStream(), getBufferSize());
		if (__fileType == ASCII_FILE_TYPE)
			input = new FromNetASCIIInputStream(input);
		// Treat everything else as binary for now
		try {
			Util.copyStream(input, local, getBufferSize(), CopyStreamEvent.UNKNOWN_STREAM_SIZE, null, false);
		} catch (IOException e) {
			try {
				socket.close();
			} catch (IOException f) {
			}
			throw e;
		}
		socket.close();
		return completePendingCommand();
	}

	/***
	 * Returns an InputStream from which a named file from the server can be
	 * read. If the current file type is ASCII, the returned InputStream will
	 * convert line separators in the file to the local representation. You must
	 * close the InputStream when you finish reading from it. The InputStream
	 * itself will take care of closing the parent data connection socket upon
	 * being closed. To finalize the file transfer you must call
	 * {@link #completePendingCommand completePendingCommand } and check its
	 * return value to verify success.
	 * <p>
	 * 
	 * @param remote
	 *            The name of the remote file.
	 * @return An InputStream from which the remote file can be read. If the
	 *         data connection cannot be opened (e.g., the file does not exist),
	 *         null is returned (in which case you may check the reply code to
	 *         determine the exact reason for failure).
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public InputStream retrieveFileStream(String remote) throws IOException {
		InputStream input;
		Socket socket;

		if ((socket = _openDataConnection_(FTPCommand.RETR, remote)) == null)
			return null;

		input = socket.getInputStream();
		if (__fileType == ASCII_FILE_TYPE) {
			// We buffer ascii transfers because the buffering has to
			// be interposed between FromNetASCIIOutputSream and the underlying
			// socket input stream. We don't buffer binary transfers
			// because we don't want to impose a buffering policy on the
			// programmer if possible. Programmers can decide on their
			// own if they want to wrap the SocketInputStream we return
			// for file types other than ASCII.
			input = new BufferedInputStream(input, getBufferSize());
			input = new FromNetASCIIInputStream(input);
		}
		return new SocketInputStream(socket, input);
	}

	/***
	 * Stores a file on the server using the given name and taking input from
	 * the given InputStream. This method does NOT close the given InputStream.
	 * If the current file type is ASCII, line separators in the file are
	 * transparently converted to the NETASCII format (i.e., you should not
	 * attempt to create a special InputStream to do this).
	 * <p>
	 * 
	 * @param remote
	 *            The name to give the remote file.
	 * @param local
	 *            The local InputStream from which to read the file.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception CopyStreamException
	 *                If an I/O error occurs while actually transferring the
	 *                file. The CopyStreamException allows you to determine the
	 *                number of bytes transferred and the IOException causing
	 *                the error. This exception may be caught either as an
	 *                IOException or independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean storeFile(String remote, InputStream local) throws IOException {
		return __storeFile(FTPCommand.STOR, remote, local);
	}

	/***
	 * Returns an OutputStream through which data can be written to store a file
	 * on the server using the given name. If the current file type is ASCII,
	 * the returned OutputStream will convert line separators in the file to the
	 * NETASCII format (i.e., you should not attempt to create a special
	 * OutputStream to do this). You must close the OutputStream when you finish
	 * writing to it. The OutputStream itself will take care of closing the
	 * parent data connection socket upon being closed. To finalize the file
	 * transfer you must call {@link #completePendingCommand
	 * completePendingCommand } and check its return value to verify success.
	 * <p>
	 * 
	 * @param remote
	 *            The name to give the remote file.
	 * @return An OutputStream through which the remote file can be written. If
	 *         the data connection cannot be opened (e.g., the file does not
	 *         exist), null is returned (in which case you may check the reply
	 *         code to determine the exact reason for failure).
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public OutputStream storeFileStream(String remote) throws IOException {
		return __storeFileStream(FTPCommand.STOR, remote);
	}

	/***
	 * Appends to a file on the server with the given name, taking input from
	 * the given InputStream. This method does NOT close the given InputStream.
	 * If the current file type is ASCII, line separators in the file are
	 * transparently converted to the NETASCII format (i.e., you should not
	 * attempt to create a special InputStream to do this).
	 * <p>
	 * 
	 * @param remote
	 *            The name of the remote file.
	 * @param local
	 *            The local InputStream from which to read the data to be
	 *            appended to the remote file.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception CopyStreamException
	 *                If an I/O error occurs while actually transferring the
	 *                file. The CopyStreamException allows you to determine the
	 *                number of bytes transferred and the IOException causing
	 *                the error. This exception may be caught either as an
	 *                IOException or independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean appendFile(String remote, InputStream local) throws IOException {
		return __storeFile(FTPCommand.APPE, remote, local);
	}

	/***
	 * Returns an OutputStream through which data can be written to append to a
	 * file on the server with the given name. If the current file type is
	 * ASCII, the returned OutputStream will convert line separators in the file
	 * to the NETASCII format (i.e., you should not attempt to create a special
	 * OutputStream to do this). You must close the OutputStream when you finish
	 * writing to it. The OutputStream itself will take care of closing the
	 * parent data connection socket upon being closed. To finalize the file
	 * transfer you must call {@link #completePendingCommand
	 * completePendingCommand } and check its return value to verify success.
	 * <p>
	 * 
	 * @param remote
	 *            The name of the remote file.
	 * @return An OutputStream through which the remote file can be appended. If
	 *         the data connection cannot be opened (e.g., the file does not
	 *         exist), null is returned (in which case you may check the reply
	 *         code to determine the exact reason for failure).
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public OutputStream appendFileStream(String remote) throws IOException {
		return __storeFileStream(FTPCommand.APPE, remote);
	}

	/***
	 * Stores a file on the server using a unique name derived from the given
	 * name and taking input from the given InputStream. This method does NOT
	 * close the given InputStream. If the current file type is ASCII, line
	 * separators in the file are transparently converted to the NETASCII format
	 * (i.e., you should not attempt to create a special InputStream to do
	 * this).
	 * <p>
	 * 
	 * @param remote
	 *            The name on which to base the unique name given to the remote
	 *            file.
	 * @param local
	 *            The local InputStream from which to read the file.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception CopyStreamException
	 *                If an I/O error occurs while actually transferring the
	 *                file. The CopyStreamException allows you to determine the
	 *                number of bytes transferred and the IOException causing
	 *                the error. This exception may be caught either as an
	 *                IOException or independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean storeUniqueFile(String remote, InputStream local) throws IOException {
		return __storeFile(FTPCommand.STOU, remote, local);
	}

	/***
	 * Returns an OutputStream through which data can be written to store a file
	 * on the server using a unique name derived from the given name. If the
	 * current file type is ASCII, the returned OutputStream will convert line
	 * separators in the file to the NETASCII format (i.e., you should not
	 * attempt to create a special OutputStream to do this). You must close the
	 * OutputStream when you finish writing to it. The OutputStream itself will
	 * take care of closing the parent data connection socket upon being closed.
	 * To finalize the file transfer you must call
	 * {@link #completePendingCommand completePendingCommand } and check its
	 * return value to verify success.
	 * <p>
	 * 
	 * @param remote
	 *            The name on which to base the unique name given to the remote
	 *            file.
	 * @return An OutputStream through which the remote file can be written. If
	 *         the data connection cannot be opened (e.g., the file does not
	 *         exist), null is returned (in which case you may check the reply
	 *         code to determine the exact reason for failure).
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public OutputStream storeUniqueFileStream(String remote) throws IOException {
		return __storeFileStream(FTPCommand.STOU, remote);
	}

	/**
	 * Stores a file on the server using a unique name assigned by the server
	 * and taking input from the given InputStream. This method does NOT close
	 * the given InputStream. If the current file type is ASCII, line separators
	 * in the file are transparently converted to the NETASCII format (i.e., you
	 * should not attempt to create a special InputStream to do this).
	 * <p>
	 * 
	 * @param local
	 *            The local InputStream from which to read the file.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception CopyStreamException
	 *                If an I/O error occurs while actually transferring the
	 *                file. The CopyStreamException allows you to determine the
	 *                number of bytes transferred and the IOException causing
	 *                the error. This exception may be caught either as an
	 *                IOException or independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 */
	public boolean storeUniqueFile(InputStream local) throws IOException {
		return __storeFile(FTPCommand.STOU, null, local);
	}

	/**
	 * Returns an OutputStream through which data can be written to store a file
	 * on the server using a unique name assigned by the server. If the current
	 * file type is ASCII, the returned OutputStream will convert line
	 * separators in the file to the NETASCII format (i.e., you should not
	 * attempt to create a special OutputStream to do this). You must close the
	 * OutputStream when you finish writing to it. The OutputStream itself will
	 * take care of closing the parent data connection socket upon being closed.
	 * To finalize the file transfer you must call
	 * {@link #completePendingCommand completePendingCommand } and check its
	 * return value to verify success.
	 * <p>
	 * 
	 * @return An OutputStream through which the remote file can be written. If
	 *         the data connection cannot be opened (e.g., the file does not
	 *         exist), null is returned (in which case you may check the reply
	 *         code to determine the exact reason for failure).
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 */
	public OutputStream storeUniqueFileStream() throws IOException {
		return __storeFileStream(FTPCommand.STOU, null);
	}

	/***
	 * Reserve a number of bytes on the server for the next file transfer.
	 * <p>
	 * 
	 * @param bytes
	 *            The number of bytes which the server should allocate.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean allocate(int bytes) throws IOException {
		return FTPReply.isPositiveCompletion(allo(bytes));
	}

	/**
	 * Reserve space on the server for the next file transfer.
	 * <p>
	 * 
	 * @param bytes
	 *            The number of bytes which the server should allocate.
	 * @param recordSize
	 *            The size of a file record.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 */
	public boolean allocate(int bytes, int recordSize) throws IOException {
		return FTPReply.isPositiveCompletion(allo(bytes, recordSize));
	}

	/***
	 * Restart a <code>STREAM_TRANSFER_MODE</code> file transfer starting from
	 * the given offset. This will only work on FTP servers supporting the REST
	 * comand for the stream transfer mode. However, most FTP servers support
	 * this. Any subsequent file transfer will start reading or writing the
	 * remote file from the indicated offset.
	 * <p>
	 * 
	 * @param offset
	 *            The offset into the remote file at which to start the next
	 *            file transfer.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	private boolean restart(long offset) throws IOException {
		__restartOffset = 0;
		return FTPReply.isPositiveIntermediate(rest(Long.toString(offset)));
	}

	/***
	 * Sets the restart offset. The restart command is sent to the server only
	 * before sending the file transfer command. When this is done, the restart
	 * marker is reset to zero.
	 * <p>
	 * 
	 * @param offset
	 *            The offset into the remote file at which to start the next
	 *            file transfer. This must be a value greater than or equal to
	 *            zero.
	 ***/
	public void setRestartOffset(long offset) {
		if (offset >= 0)
			__restartOffset = offset;
	}

	/***
	 * Fetches the restart offset.
	 * <p>
	 * 
	 * @return offset The offset into the remote file at which to start the next
	 *         file transfer.
	 ***/
	public long getRestartOffset() {
		return __restartOffset;
	}

	/***
	 * Renames a remote file.
	 * <p>
	 * 
	 * @param from
	 *            The name of the remote file to rename.
	 * @param to
	 *            The new name of the remote file.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean rename(String from, String to) throws IOException {
		if (!FTPReply.isPositiveIntermediate(rnfr(from)))
			return false;

		return FTPReply.isPositiveCompletion(rnto(to));
	}

	/***
	 * Abort a transfer in progress.
	 * <p>
	 * 
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean abort() throws IOException {
		return FTPReply.isPositiveCompletion(abor());
	}

	/***
	 * Deletes a file on the FTP server.
	 * <p>
	 * 
	 * @param pathname
	 *            The pathname of the file to be deleted.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean deleteFile(String pathname) throws IOException {
		return FTPReply.isPositiveCompletion(dele(pathname));
	}

	/***
	 * Removes a directory on the FTP server (if empty).
	 * <p>
	 * 
	 * @param pathname
	 *            The pathname of the directory to remove.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean removeDirectory(String pathname) throws IOException {
		return FTPReply.isPositiveCompletion(rmd(pathname));
	}

	/***
	 * Creates a new subdirectory on the FTP server in the current directory (if
	 * a relative pathname is given) or where specified (if an absolute pathname
	 * is given).
	 * <p>
	 * 
	 * @param pathname
	 *            The pathname of the directory to create.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean makeDirectory(String pathname) throws IOException {
		return FTPReply.isPositiveCompletion(mkd(pathname));
	}

	/***
	 * Returns the pathname of the current working directory.
	 * <p>
	 * 
	 * @return The pathname of the current working directory. If it cannot be
	 *         obtained, returns null.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public String printWorkingDirectory() throws IOException {
		if (pwd() != FTPReply.PATHNAME_CREATED)
			return null;

		return __parsePathname((String) _replyLines.elementAt(0));
	}

	/**
	 * Send a site specific command.
	 * 
	 * @param arguments
	 *            The site specific command and arguments.
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 */
	public boolean sendSiteCommand(String arguments) throws IOException {
		return FTPReply.isPositiveCompletion(site(arguments));
	}

	/***
	 * Fetches the system type name from the server and returns the string. This
	 * value is cached for the duration of the connection after the first call
	 * to this method. In other words, only the first time that you invoke this
	 * method will it issue a SYST command to the FTP server. FTPClient will
	 * remember the value and return the cached value until a call to
	 * disconnect.
	 * <p>
	 * 
	 * @return The system type name obtained from the server. null if the
	 *         information could not be obtained.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public String getSystemName() throws IOException {
		// if (syst() == FTPReply.NAME_SYSTEM_TYPE)
		// Technically, we should expect a NAME_SYSTEM_TYPE response, but
		// in practice FTP servers deviate, so we soften the condition to
		// a positive completion.
		if (__systemName == null && FTPReply.isPositiveCompletion(syst()))
			__systemName = ((String) _replyLines.elementAt(0)).substring(4);

		return __systemName;
	}

	/***
	 * Fetches the system help information from the server and returns the full
	 * string.
	 * <p>
	 * 
	 * @return The system help string obtained from the server. null if the
	 *         information could not be obtained.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public String listHelp() throws IOException {
		if (FTPReply.isPositiveCompletion(help()))
			return getReplyString();
		return null;
	}

	/**
	 * Fetches the help information for a given command from the server and
	 * returns the full string.
	 * 
	 * @param command
	 *            The command on which to ask for help.
	 * @return The command help string obtained from the server. null if the
	 *         information could not be obtained.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 */
	public String listHelp(String command) throws IOException {
		if (FTPReply.isPositiveCompletion(help(command)))
			return getReplyString();
		return null;
	}

	/***
	 * Sends a NOOP command to the FTP server. This is useful for preventing
	 * server timeouts.
	 * <p>
	 * 
	 * @return True if successfully completed, false if not.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public boolean sendNoOp() throws IOException {
		return FTPReply.isPositiveCompletion(noop());
	}

	/***
	 * Obtain a list of filenames in a directory (or just the name of a given
	 * file, which is not particularly useful). This information is obtained
	 * through the NLST command. If the given pathname is a directory and
	 * contains no files, a zero length array is returned only if the FTP server
	 * returned a positive completion code, otherwise null is returned (the FTP
	 * server returned a 550 error No files found.). If the directory is not
	 * empty, an array of filenames in the directory is returned. If the
	 * pathname corresponds to a file, only that file will be listed. The server
	 * may or may not expand glob expressions.
	 * <p>
	 * 
	 * @param pathname
	 *            The file or directory to list.
	 * @return The list of filenames contained in the given path. null if the
	 *         list could not be obtained. If there are no filenames in the
	 *         directory, a zero-length array is returned.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public String[] listNames(String pathname) throws IOException {
		String line;
		Socket socket;
		BufferedReader reader;
		Vector results;

		if ((socket = _openDataConnection_(FTPCommand.NLST, pathname)) == null)
			return null;

		reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding()));

		results = new Vector();
		while ((line = reader.readLine()) != null)
			results.addElement(line);
		reader.close();
		socket.close();

		if (completePendingCommand()) {
			String[] result;
			result = new String[results.size()];
			results.copyInto(result);
			return result;
		}

		return null;
	}

	/***
	 * Obtain a list of filenames in the current working directory This
	 * information is obtained through the NLST command. If the current
	 * directory contains no files, a zero length array is returned only if the
	 * FTP server returned a positive completion code, otherwise, null is
	 * returned (the FTP server returned a 550 error No files found.). If the
	 * directory is not empty, an array of filenames in the directory is
	 * returned.
	 * <p>
	 * 
	 * @return The list of filenames contained in the current working directory.
	 *         null if the list could not be obtained. If there are no filenames
	 *         in the directory, a zero-length array is returned.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public String[] listNames() throws IOException {
		return listNames(null);
	}

	/**
	 * Using the supplied <code>parserKey</code>, obtain a list of file
	 * information for the current working directory or for just a single file.
	 * <p>
	 * If <code>key</code> is null, this object will try to autodetect the
	 * system-type/parser-type by calling the SYST command.
	 * <p>
	 * Under the DefaultFTPFileEntryParserFactory, which is used unless a
	 * different factory has been specified, the key can be either a recognized
	 * System type for which a parser has been defined, or the fully qualified
	 * class name of a class that implements
	 * org.apache.commons.net.ftp.FTPFileEntryParser.
	 * <p>
	 * This information is obtained through the LIST command. The contents of
	 * the returned array is determined by the<code> FTPFileEntryParser </code>
	 * used.
	 * <p>
	 * 
	 * @param parserKey
	 *            This is a "handle" which the parser factory used must be able
	 *            to resolve into a class implementing FTPFileEntryParser.
	 *            <p>
	 *            In the DefaultFTPFileEntryParserFactory, this may either be a
	 *            specific key identifying a server type, which is used to
	 *            identify a parser type, or the fully qualified class name of
	 *            the parser. See
	 *            DefaultFTPFileEntryParserFactory.createFileEntryParser for
	 *            full details.
	 *            <p>
	 *            If this parameter is null, will attempt to generate a key by
	 *            running the SYST command. This should cause no problem with
	 *            the functionality implemented in the
	 *            DefaultFTPFileEntryParserFactory, but may not map so well to
	 *            an alternative user-created factory. If that is the case,
	 *            calling this routine with a null parameter and a custom parser
	 *            factory may not be advisable.
	 *            <p>
	 * @param pathname
	 *            The file or directory to list. Since the server may or may not
	 *            expand glob expressions, using them here is not recommended
	 *            and may well cause this method to fail.
	 * 
	 * @return The list of file information contained in the given path in the
	 *         format determined by the parser represented by the
	 *         <code> parserKey </code> parameter.
	 *         <p>
	 *         <b> NOTE:</b> This array may contain null members if any of the
	 *         individual file listings failed to parse. The caller should check
	 *         each entry for null before referencing it.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 * @exception ParserInitializationException
	 *                Thrown if the parserKey parameter cannot be resolved by
	 *                the selected parser factory. In the
	 *                DefaultFTPEntryParserFactory, this will happen when
	 *                parserKey is neither the fully qualified class name of a
	 *                class implementing the interface
	 *                org.apache.commons.net.ftp.FTPFileEntryParser nor a string
	 *                containing one of the recognized keys mapping to such a
	 *                parser or if class loader security issues prevent its
	 *                being loaded.
	 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
	 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
	 * @see org.apache.commons.net.ftp.FTPFileEntryParser
	 * @deprecated use {@link #listFiles() listFiles()} or
	 *             {@link #listFiles(String) listFiles(String)} instead and
	 *             specify the parser Key in an {@link #FTPClientConfig
	 *             FTPClientConfig} object instead.
	 */
	public FTPFile[] listFiles(String parserKey, String pathname) throws IOException {
		FTPListParseEngine engine = initiateListParsing(parserKey, pathname);
		return engine.getFiles();
	}

	/**
	 * Using the default system autodetect mechanism, obtain a list of file
	 * information for the current working directory or for just a single file.
	 * <p>
	 * This information is obtained through the LIST command. The contents of
	 * the returned array is determined by the<code> FTPFileEntryParser </code>
	 * used.
	 * <p>
	 * 
	 * @param pathname
	 *            The file or directory to list. Since the server may or may not
	 *            expand glob expressions, using them here is not recommended
	 *            and may well cause this method to fail.
	 * 
	 * @return The list of file information contained in the given path in the
	 *         format determined by the autodetection mechanism
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 * @exception ParserInitializationException
	 *                Thrown if the parserKey parameter cannot be resolved by
	 *                the selected parser factory. In the
	 *                DefaultFTPEntryParserFactory, this will happen when
	 *                parserKey is neither the fully qualified class name of a
	 *                class implementing the interface
	 *                org.apache.commons.net.ftp.FTPFileEntryParser nor a string
	 *                containing one of the recognized keys mapping to such a
	 *                parser or if class loader security issues prevent its
	 *                being loaded.
	 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
	 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
	 * @see org.apache.commons.net.ftp.FTPFileEntryParser
	 */
	public FTPFile[] listFiles(String pathname) throws IOException {
		String key = null;
		FTPListParseEngine engine = initiateListParsing(key, pathname);
		return engine.getFiles();

	}

	/**
	 * Using the default system autodetect mechanism, obtain a list of file
	 * information for the current working directory.
	 * <p>
	 * This information is obtained through the LIST command. The contents of
	 * the returned array is determined by the<code> FTPFileEntryParser </code>
	 * used.
	 * <p>
	 * 
	 * @return The list of file information contained in the current directory
	 *         in the format determined by the autodetection mechanism.
	 *         <p>
	 *         <b> NOTE:</b> This array may contain null members if any of the
	 *         individual file listings failed to parse. The caller should check
	 *         each entry for null before referencing it.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 * @exception ParserInitializationException
	 *                Thrown if the parserKey parameter cannot be resolved by
	 *                the selected parser factory. In the
	 *                DefaultFTPEntryParserFactory, this will happen when
	 *                parserKey is neither the fully qualified class name of a
	 *                class implementing the interface
	 *                org.apache.commons.net.ftp.FTPFileEntryParser nor a string
	 *                containing one of the recognized keys mapping to such a
	 *                parser or if class loader security issues prevent its
	 *                being loaded.
	 * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
	 * @see org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory
	 * @see org.apache.commons.net.ftp.FTPFileEntryParser
	 */
	public FTPFile[] listFiles() throws IOException {
		return listFiles((String) null);
	}

	/**
	 * Using the default autodetect mechanism, initialize an FTPListParseEngine
	 * object containing a raw file information for the current working
	 * directory on the server This information is obtained through the LIST
	 * command. This object is then capable of being iterated to return a
	 * sequence of FTPFile objects with information filled in by the
	 * <code> FTPFileEntryParser </code> used.
	 * <p>
	 * This method differs from using the listFiles() methods in that expensive
	 * FTPFile objects are not created until needed which may be an advantage on
	 * large lists.
	 * 
	 * @return A FTPListParseEngine object that holds the raw information and is
	 *         capable of providing parsed FTPFile objects, one for each file
	 *         containing information contained in the given path in the format
	 *         determined by the <code> parser </code> parameter. Null will be
	 *         returned if a data connection cannot be opened. If the current
	 *         working directory contains no files, an empty array will be the
	 *         return.
	 * 
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 * @exception ParserInitializationException
	 *                Thrown if the autodetect mechanism cannot resolve the type
	 *                of system we are connected with.
	 * @see FTPListParseEngine
	 */
	public FTPListParseEngine initiateListParsing() throws IOException {
		return initiateListParsing((String) null);
	}

	/**
	 * Using the default autodetect mechanism, initialize an FTPListParseEngine
	 * object containing a raw file information for the supplied directory. This
	 * information is obtained through the LIST command. This object is then
	 * capable of being iterated to return a sequence of FTPFile objects with
	 * information filled in by the <code> FTPFileEntryParser </code> used.
	 * <p>
	 * The server may or may not expand glob expressions. You should avoid using
	 * glob expressions because the return format for glob listings differs from
	 * server to server and will likely cause this method to fail.
	 * <p>
	 * This method differs from using the listFiles() methods in that expensive
	 * FTPFile objects are not created until needed which may be an advantage on
	 * large lists.
	 * <p>
	 * 
	 * <pre>
	 * FTPClient f = FTPClient();
	 * f.connect(server);
	 * f.login(username, password);
	 * FTPListParseEngine engine = f.initiateListParsing(directory);
	 * 
	 * while (engine.hasNext()) {
	 * 	FTPFile[] files = engine.getNext(25); // &quot;page size&quot; you want
	 * 	// do whatever you want with these files, display them, etc.
	 * 	// expensive FTPFile objects not created until needed.
	 * }
	 * </pre>
	 * 
	 * @return A FTPListParseEngine object that holds the raw information and is
	 *         capable of providing parsed FTPFile objects, one for each file
	 *         containing information contained in the given path in the format
	 *         determined by the <code> parser </code> parameter. Null will be
	 *         returned if a data connection cannot be opened. If the current
	 *         working directory contains no files, an empty array will be the
	 *         return.
	 * 
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 * @exception ParserInitializationException
	 *                Thrown if the autodetect mechanism cannot resolve the type
	 *                of system we are connected with.
	 * @see FTPListParseEngine
	 */
	public FTPListParseEngine initiateListParsing(String pathname) throws IOException {
		String key = null;
		return initiateListParsing(key, pathname);
	}

	/**
	 * Using the supplied parser key, initialize an FTPListParseEngine object
	 * containing a raw file information for the supplied directory. This
	 * information is obtained through the LIST command. This object is then
	 * capable of being iterated to return a sequence of FTPFile objects with
	 * information filled in by the <code> FTPFileEntryParser </code> used.
	 * <p>
	 * The server may or may not expand glob expressions. You should avoid using
	 * glob expressions because the return format for glob listings differs from
	 * server to server and will likely cause this method to fail.
	 * <p>
	 * This method differs from using the listFiles() methods in that expensive
	 * FTPFile objects are not created until needed which may be an advantage on
	 * large lists.
	 * 
	 * @param parserKey
	 *            A string representing a designated code or fully-qualified
	 *            class name of an <code> FTPFileEntryParser </code> that should
	 *            be used to parse each server file listing.
	 * 
	 * @return A FTPListParseEngine object that holds the raw information and is
	 *         capable of providing parsed FTPFile objects, one for each file
	 *         containing information contained in the given path in the format
	 *         determined by the <code> parser </code> parameter. Null will be
	 *         returned if a data connection cannot be opened. If the current
	 *         working directory contains no files, an empty array will be the
	 *         return.
	 * 
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 * @exception ParserInitializationException
	 *                Thrown if the parserKey parameter cannot be resolved by
	 *                the selected parser factory. In the
	 *                DefaultFTPEntryParserFactory, this will happen when
	 *                parserKey is neither the fully qualified class name of a
	 *                class implementing the interface
	 *                org.apache.commons.net.ftp.FTPFileEntryParser nor a string
	 *                containing one of the recognized keys mapping to such a
	 *                parser or if class loader security issues prevent its
	 *                being loaded.
	 * @see FTPListParseEngine
	 */
	public FTPListParseEngine initiateListParsing(String parserKey, String pathname) throws IOException {
		// We cache the value to avoid creation of a new object every
		// time a file listing is generated.
		if (__entryParser == null) {
			if (null != parserKey) {
				// if a parser key was supplied in the parameters,
				// use that to create the paraser
				__entryParser = __parserFactory.createFileEntryParser(parserKey);

			} else {
				// if no parserKey was supplied, check for a configuration
				// in the params, and if non-null, use that.
				if (null != __configuration) {
					__entryParser = __parserFactory.createFileEntryParser(__configuration);
				} else {
					// if a parserKey hasn't been supplied, and a configuration
					// hasn't been supplied, then autodetect by calling
					// the SYST command and use that to choose the parser.
					__entryParser = __parserFactory.createFileEntryParser(getSystemName());
				}
			}
		}

		return initiateListParsing(__entryParser, pathname);

	}

	/**
	 * private method through which all listFiles() and initiateListParsing
	 * methods pass once a parser is determined.
	 * 
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 * @see FTPListParseEngine
	 */
	private FTPListParseEngine initiateListParsing(FTPFileEntryParser parser, String pathname) throws IOException {
		Socket socket;

		FTPListParseEngine engine = new FTPListParseEngine(parser);
		if ((socket = _openDataConnection_(FTPCommand.LIST, pathname)) == null) {
			return engine;
		}

		engine.readServerList(socket.getInputStream(), getControlEncoding());

		socket.close();

		completePendingCommand();
		return engine;
	}

	/***
	 * Issue the FTP STAT command to the server.
	 * <p>
	 * 
	 * @return The status information returned by the server.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public String getStatus() throws IOException {
		if (FTPReply.isPositiveCompletion(stat()))
			return getReplyString();
		return null;
	}

	/***
	 * Issue the FTP STAT command to the server for a given pathname. This
	 * should produce a listing of the file or directory.
	 * <p>
	 * 
	 * @return The status information returned by the server.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 ***/
	public String getStatus(String pathname) throws IOException {
		if (FTPReply.isPositiveCompletion(stat(pathname)))
			return getReplyString();
		return null;
	}

	/**
	 * Using a programmer specified <code> FTPFileListParser </code>, obtain a
	 * list of file information for a directory or information for just a single
	 * file. This information is obtained through the LIST command. The contents
	 * of the returned array is determined by the
	 * <code> FTPFileListParser </code> used. The server may or may not expand
	 * glob expressions. You should avoid using glob expressions because the
	 * return format for glob listings differs from server to server and will
	 * likely cause this method to fail.
	 * <p>
	 * 
	 * @param parser
	 *            The <code> FTPFileListParser </code> that should be used to
	 *            parse the server file listing.
	 * @param pathname
	 *            The file or directory to list.
	 * @return The list of file information contained in the given path in the
	 *         format determined by the <code> parser </code> parameter.
	 *         <p>
	 *         <b> NOTE:</b> This array may contain null members if any of the
	 *         individual file listings failed to parse. The caller should check
	 *         each entry for null before referencing it.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 * 
	 * @return The list of file information contained in the given path in the
	 *         format determined by<code> parserKey </code>parameter.
	 *         <p>
	 *         <b> NOTE:</b> This array may contain null members if any of the
	 *         individual file listings failed to parse. The caller should check
	 *         each entry for null before referencing it.
	 * 
	 * @exception IOException
	 * @since 5 Jan 2004
	 * @deprecated use listFiles(String parserKey, String pathname) instead
	 */
	public FTPFile[] listFiles(FTPFileListParser parser, String pathname) throws IOException {
		Socket socket;
		FTPFile[] results;

		if ((socket = _openDataConnection_(FTPCommand.LIST, pathname)) == null)
			return new FTPFile[0];

		results = parser.parseFileList(socket.getInputStream(), getControlEncoding());

		socket.close();

		completePendingCommand();

		return results;
	}

	/**
	 * Using a programmer specified <code> FTPFileListParser </code>, obtain a
	 * list of file information for the current working directory. This
	 * information is obtained through the LIST command. The contents of the
	 * array returned is determined by the <code> FTPFileListParser </code>
	 * used.
	 * <p>
	 * 
	 * @param parser
	 *            The <code> FTPFileListParser </code> that should be used to
	 *            parse the server file listing.
	 * 
	 * @return The list of file information contained in the given path in the
	 *         format determined by the <code> parser </code> parameter.
	 *         <p>
	 *         <b> NOTE:</b> This array may contain null members if any of the
	 *         individual file listings failed to parse. The caller should check
	 *         each entry for null before referencing it.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 * @exception IOException
	 * @since 5 Jan 2004
	 * @deprecated use listFiles(String parserKey) instead.
	 */
	public FTPFile[] listFiles(FTPFileListParser parser) throws IOException {
		return listFiles(parser, null);
	}

	/**
	 * Using a programmer specified <code> FTPFileEntryParser </code>,
	 * initialize an object containing a raw file information for the current
	 * working directory. This information is obtained through the LIST command.
	 * This object is then capable of being iterated to return a sequence of
	 * FTPFile objects with information filled in by the
	 * <code> FTPFileEntryParser </code> used.
	 * <p>
	 * The server may or may not expand glob expressions. You should avoid using
	 * glob expressions because the return format for glob listings differs from
	 * server to server and will likely cause this method to fail.
	 * <p>
	 * This method differs from using the listFiles() methods in that expensive
	 * FTPFile objects are not created until needed which may be an advantage on
	 * large lists.
	 * 
	 * @param parser
	 *            The <code> FTPFileEntryParser </code> that should be used to
	 *            parse each server file listing.
	 * 
	 * @return An iteratable object that holds the raw information and is
	 *         capable of providing parsed FTPFile objects, one for each file
	 *         containing information contained in the given path in the format
	 *         determined by the <code> parser </code> parameter. Null will be
	 *         returned if a data connection cannot be opened. If the current
	 *         working directory contains no files, an empty array will be the
	 *         return.
	 * 
	 *         <pre>
	 * FTPClient f = FTPClient();
	 * f.connect(server);
	 * f.login(username, password);
	 * FTPFileList list = f.createFileList(directory, parser);
	 * FTPFileIterator iter = list.iterator();
	 * 
	 * while (iter.hasNext()) {
	 * 	FTPFile[] files = iter.getNext(25); // &quot;page size&quot; you want
	 * 	// do whatever you want with these files, display them, etc.
	 * 	// expensive FTPFile objects not created until needed.
	 * }
	 * </pre>
	 * 
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 * @deprecated - use initiateListParsing(FTPFileEntryParser) method instead.
	 * @see FTPFileList
	 */
	public FTPFileList createFileList(FTPFileEntryParser parser) throws IOException {
		return createFileList(null, parser);
	}

	/**
	 * Using a programmer specified <code> FTPFileEntryParser </code>,
	 * initialize an object containing a raw file information for a directory or
	 * information for a single file. This information is obtained through the
	 * LIST command. This object is then capable of being iterated to return a
	 * sequence of FTPFile objects with information filled in by the
	 * <code> FTPFileEntryParser </code> used. The server may or may not expand
	 * glob expressions. You should avoid using glob expressions because the
	 * return format for glob listings differs from server to server and will
	 * likely cause this method to fail.
	 * <p>
	 * 
	 * @param parser
	 *            The <code> FTPFileEntryParser </code> that should be used to
	 *            parse each server file listing.
	 * @param pathname
	 *            The file or directory to list.
	 * @return An iteratable object that holds the raw information and is
	 *         capable of providing parsed FTPFile objects, one for each file
	 *         containing information contained in the given path in the format
	 *         determined by the <code> parser </code> parameter. Null will be
	 *         returned if a data connection cannot be opened. If the supplied
	 *         path contains no files, an empty array will be the return.
	 * @exception FTPConnectionClosedException
	 *                If the FTP server prematurely closes the connection as a
	 *                result of the client being idle or some other reason
	 *                causing the server to send FTP reply code 421. This
	 *                exception may be caught either as an IOException or
	 *                independently as itself.
	 * @exception IOException
	 *                If an I/O error occurs while either sending a command to
	 *                the server or receiving a reply from the server.
	 * @deprecated - use initiateListParsing(String, FTPFileEntryParser) method
	 *             instead.
	 * @see FTPFileList
	 */
	public FTPFileList createFileList(String pathname, FTPFileEntryParser parser) throws IOException {
		Socket socket;

		if ((socket = _openDataConnection_(FTPCommand.LIST, pathname)) == null) {
			return null;
		}

		FTPFileList list = FTPFileList.create(socket.getInputStream(), parser);

		socket.close();

		completePendingCommand();
		return list;
	}

	/**
	 * Set the internal buffer size.
	 * 
	 * @param bufSize
	 *            The size of the buffer
	 */
	public void setBufferSize(int bufSize) {
		__bufferSize = bufSize;
	}

	/**
	 * Retrieve the current internal buffer size.
	 * 
	 * @return The current buffer size.
	 */
	public int getBufferSize() {
		return __bufferSize;
	}

	/**
	 * Implementation of the {@link Configurable Configurable} interface. In the
	 * case of this class, configuring merely makes the config object available
	 * for the factory methods that construct parsers.
	 * 
	 * @param config
	 *            {@link FTPClientConfig FTPClientConfig} object used to provide
	 *            non-standard configurations to the parser.
	 * @since 1.4
	 */
	public void configure(FTPClientConfig config) {
		this.__configuration = config;
	}

}

/*
 * Emacs configuration Local variables: ** mode: java ** c-basic-offset: 4 **
 * indent-tabs-mode: nil ** End: **
 */
